package com.misc.tunewsreader;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Picture;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.DownloadListener;
import android.webkit.WebView;
import android.webkit.WebView.PictureListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.markupartist.android.widget.ActionBar;
import com.markupartist.android.widget.ActionBar.AbstractAction;
import com.misc.tunewsreader.TUNewsReaderActivity.OfflineModeAction;

public class PostHierarchy extends Activity {
	private ReplyAdapter adapter;
	public String current_message_id, current_message, current_message_subject;
	public int current_message_idx;
	public static String current_message_date;
	public static String current_message_author;
	public static final int Menu_reply = Menu.FIRST + 1;
	public static final int Menu_asread = Menu.FIRST + 1;
	public static final int Menu_asunread = Menu.FIRST + 2;
	public static final int Menu_share = Menu.FIRST + 3;
	public static final int Menu_sub_asread = Menu.FIRST + 4;
	public static final int Menu_sub_asunread = Menu.FIRST + 5;
	public static final int Menu_cancel = Menu.FIRST + 6;
	public static MenuItem m_reply;

	// private static String CANCEL_GROUP = "all.all.ctl";

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.hierarchy);

		final Bundle extras = getIntent().getExtras();
		long thread_id = extras.getLong("ThreadId");

		List<NNTPPost> replies = NNTPClient.getReplies(NNTPClient
				.getThreadById(thread_id));
		if (replies == null) {
			// some error occured
			this.finish();
		}

		NNTPPost first_post = NNTPClient.getPostById(thread_id);
		first_post.setLayer(-1);

		replies.add(0, first_post);

		showPost(first_post);

		ListView reply_list = (ListView) findViewById(R.id.posts);
		adapter = new ReplyAdapter(this, R.layout.reply_title, replies);
		adapter.setMarked(thread_id);
		reply_list.setAdapter(adapter);
		reply_list.setOnItemClickListener(post_clicked);
		registerForContextMenu(reply_list);

		ActionBar bar = (ActionBar) findViewById(R.id.actionbar);
		bar.setTitle(first_post.getHeader().getSubject());
		// info and reply is only available in online mode
		if (!NNTPClient.isOfflineMode()) {
			bar.addAction(new InfoAction(this, R.drawable.bar_info));
			bar.addAction(new ReplyAction(this, R.drawable.bar_reply));
		} else {
			bar.addAction(new OfflineModeAction(this, R.drawable.bar_warning));
		}
		bar.setDisplayHomeAsUpEnabled(true);
		bar.setOnTitleClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				finish();
			}
		});

	}

	@Override
	public void onSaveInstanceState(Bundle savedInstanceState) {
		super.onSaveInstanceState(savedInstanceState);
		Parcelable reply_state = ((ListView) findViewById(R.id.posts))
				.onSaveInstanceState();
		savedInstanceState.putParcelable("reply_state", reply_state);
		savedInstanceState.putInt("current_post", current_message_idx);
	}

	@Override
	public void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);

		if (savedInstanceState != null) {
			// restore reply listview state
			((ListView) findViewById(R.id.posts))
					.onRestoreInstanceState(savedInstanceState
							.getParcelable("reply_state"));
			// show same post
			current_message_idx = savedInstanceState.getInt("current_post");
			((ListView) findViewById(R.id.posts)).performItemClick(null,
					current_message_idx, 0);
		}
	}

	public static class ReplyAction extends AbstractAction {
		private Context mContext;

		public ReplyAction(Context context, int drawable) {
			super(drawable);
			mContext = context;
		}

		@Override
		public void performAction(View view) {
			final Intent intent = new Intent(mContext.getApplicationContext(),
					WritePost.class);
			intent.putExtra("newsgroup", NNTPClient.getCurrentGroup().getName());
			intent.putExtra("reply",
					((PostHierarchy) mContext).current_message_id);
			intent.putExtra("reply_text",
					((PostHierarchy) mContext).current_message);
			intent.putExtra("reply_subject",
					((PostHierarchy) mContext).current_message_subject);
			// get reply header
			String reply_header = mContext.getString(R.string.reply_header);
			reply_header = reply_header.replace("$date", current_message_date)
					.replace("$author", current_message_author);
			intent.putExtra("reply_header", reply_header);
			((PostHierarchy) mContext).startActivity(intent);

		}
	}

	public static class InfoAction extends AbstractAction {
		private Context mContext;

		public InfoAction(Context context, int drawable) {
			super(drawable);
			mContext = context;
		}

		@Override
		public void performAction(View view) {
			final Intent intent = new Intent(mContext.getApplicationContext(),
					SourceView.class);
			intent.putExtra("post",
					(String) ((PostHierarchy) mContext).current_message_id);
			((PostHierarchy) mContext).startActivity(intent);
		}
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo menuInfo) {
		if (v.getId() == R.id.posts) {
			AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
			NNTPPost thread = (NNTPPost) adapter.getItem(info.position);

			menu.setHeaderTitle(getApplicationContext().getString(
					R.string.post_menu_title));
			menu.add(Menu.NONE, Menu_asread, 0, getApplicationContext()
					.getString(R.string.mark_as_read));
			menu.add(Menu.NONE, Menu_asunread, 1, getApplicationContext()
					.getString(R.string.mark_as_unread));
			menu.add(Menu.NONE, Menu_share, 2, getApplicationContext()
					.getString(R.string.share));
			menu.add(Menu.NONE, Menu_sub_asread, 3, "Mark (sub-)thread as read");
			menu.add(Menu.NONE, Menu_sub_asunread, 4,
					"Mark (sub-)thread as unread");

			// if we are author, we can cancel post
			SharedPreferences prefs = PreferenceManager
					.getDefaultSharedPreferences(getApplicationContext());
			String sender = NNTPClient.formatSender(
					prefs.getString("pref_username", "Anonymous"),
					prefs.getString("pref_mail", "an@nym.us"));
			if (thread.getHeader().getAuthor().equals(sender)) {
				menu.add(Menu.NONE, Menu_cancel, 5, "Cancel post");
			}

			Log.d("NNTPCancel", "Cancel: author = "
					+ thread.getHeader().getAuthor());
		}
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item
				.getMenuInfo();

		NNTPPost thread = (NNTPPost) adapter.getItem(info.position);

		switch (item.getItemId()) {
		case Menu_asread:
			thread.setRead(true);
			adapter.notifyDataSetChanged();
			break;

		case Menu_asunread:
			thread.setRead(false);
			adapter.notifyDataSetChanged();
			break;

		case Menu_share:
			final Intent intent = new Intent(Intent.ACTION_SEND);
			intent.setType("text/plain");
			intent.putExtra(Intent.EXTRA_TEXT, thread.getData());
			intent.putExtra(Intent.EXTRA_SUBJECT, getApplicationContext()
					.getString(R.string.forward)
					+ " "
					+ thread.getHeader().getSubject());
			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			Intent.createChooser(intent, "Share");
			getApplicationContext().startActivity(intent);
			break;

		case Menu_sub_asunread:
		case Menu_sub_asread:
			boolean read = (item.getItemId() == Menu_sub_asread) ? true : false;

			int position = info.position + 1;
			NNTPPost post = thread;
			int layer = post.getLayer();
			post.setRead(read);

			Log.d("NNTP", "Layer: " + layer);
			while (position < adapter.getCount()
					&& (thread.getHeader().getThreadId() == post.getHeader()
							.getThreadId() || post.getLayer() > layer)) {
				post = adapter.getItem(position);
				if (post.getLayer() > layer) {
					Log.d("NNTP", "Set (un)read, layer " + post.getLayer());
					post.setRead(read);
				}
				position++;
			}
			adapter.notifyDataSetChanged();
			break;

		case Menu_cancel:
			Log.d("NNTP", "Cancel post " + thread.getHeader().getMessageID());
			SharedPreferences prefs = PreferenceManager
					.getDefaultSharedPreferences(getApplicationContext());
			if (NNTPClient.postControlMessage(NNTPClient.getCurrentGroup()
					.getName(), "cancel " + thread.getHeader().getMessageID(),
					NNTPClient.formatSender(
							prefs.getString("pref_username", ""),
							prefs.getString("pref_mail", "")),
					getApplicationContext().getString(R.string.cancel_message))) {
				// post cancelled
				NNTPClient.cancelPost(NNTPClient.getCurrentGroup().getName(),
						thread);
				adapter.remove(adapter.getItem(info.position));
				adapter.notifyDataSetChanged();
				Toast.makeText(getApplicationContext(),
						getString(R.string.cancel_successful),
						Toast.LENGTH_SHORT).show();
			} else {
				Toast.makeText(getApplicationContext(),
						getString(R.string.cancel_failed), Toast.LENGTH_SHORT)
						.show();
			}
			break;
		}

		return true;
	}

	OnItemClickListener post_clicked = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			NNTPPost thread = adapter.getItem(position);
			if (thread == null)
				return;

			current_message_idx = position;

			adapter.setMarked(thread.getHeader().getThreadId());
			adapter.notifyDataSetChanged();

			showPost(thread);

		}
	};

	private void showPost(NNTPPost post) {
		current_message_id = post.getHeader().getMessageID();
		current_message = post.getData();
		current_message_subject = post.getHeader().getSubject();
		current_message_date = post.getHeader().getDate();
		current_message_author = post.getHeader().getAuthorName();

		ActionBar bar = (ActionBar) findViewById(R.id.actionbar);
		bar.setTitle(post.getHeader().getSubject());

		final WebView post_view = (WebView) findViewById(R.id.post_dbg);
		/*
		 * WebSettings settings = post_view.getSettings();
		 * settings.setSupportZoom(true); settings.setBuiltInZoomControls(true);
		 */

		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(getApplicationContext());

		String disp = post.getDataHTML();

		// set font type
		if (prefs.getBoolean("pref_fixed_font", true)) {
			disp = disp.replaceFirst("%1", "Monospace");
			Log.d("NNTP", "Monospace!");
		} else {
			disp = disp.replaceFirst("%1", "Inherit");
		}

		// set fontsize
		disp = disp
				.replaceFirst("%2", prefs.getString("pref_fontsize", "100%"));

		Log.d("NNTP", "Post encoding: " + post.getHeader().getCharset());

		// show smileys
		if (prefs.getBoolean("pref_smileys", true)) {
			SmileyParser parser = new SmileyParser();
			parser.init();
			disp = parser.parse(disp);
		}

		// simple formatting
		if (prefs.getBoolean("pref_format", true)) {
			disp = disp.replaceAll("(^|\\s)(/\\S[^\\n]+\\S/)(\\s|,|$)",
					"$1<i>$2</i>$3");
			disp = disp.replaceAll("(^|\\s)(_\\S[^\\n]+\\S_)(\\s|,|$)",
					"$1<u>$2</u>$3");
			disp = disp.replaceAll("(^|\\s)(\\*\\S[^\\n]+\\S\\*)(\\s|,|$)",
					"$1<b>$2</b>$3");
		}

		// make urls clickable
		if (prefs.getBoolean("pref_url", true)) {
			disp = disp
					.replaceAll(
							"((http|ftp|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?)",
							"<a href=\"$1\">$1</a>");
		}

		// embedded images
		disp = disp.replace("%attach", "<hr /><img");
		disp = disp.replace("%dlattach", "<hr /><div class='attachment'><img src=\"file:///android_asset/attach.png\" style=\"vertical-align: middle;\"/><a href=");
		disp = disp.replace("%dlendattach", "</a></div>");
		
		// workaround to force webview to scroll to top:
		// load blank page, wait until loaded (no scrollbars -> same as
		// scrolling to top), then load real page (which inherits scroll
		// position). therefore scroll position is (0,0)
		final String src = disp;
		post_view.setPictureListener(new PictureListener() {
			@Override
			public void onNewPicture(WebView view, Picture picture) {
				post_view.setPictureListener(null);
				post_view.loadDataWithBaseURL("file:///android_asset/", src,
						"text/html", "utf-8", null);
			}
		});

		post_view.setDownloadListener(new DownloadListener() {
			public void onDownloadStart(String url, String userAgent,
					String contentDisposition, String mimetype,
					long contentLength) {
				/*
				 * Intent i = new Intent(Intent.ACTION_VIEW);
				 * i.setData(Uri.parse(url)); startActivity(i);
				 */
				try {
					String filename = url.substring(url.indexOf("charset=") + 9, url.indexOf(";base64") - 1);
					Log.d("NNTP", "attach-filename: " + filename);
					File outputFile = new File(Environment
							.getExternalStorageDirectory(), filename);
					FileOutputStream w = new FileOutputStream(outputFile);
					byte[] raw = OwnBase64.decode(url.substring(url.indexOf(";base64,") + 8));
					w.write(raw);
					w.close();

					Intent i = new Intent(Intent.ACTION_VIEW);
					i.setData(Uri.parse(outputFile.toURI().toString()
							.replace("file:/", "file:///")));
					startActivity(i);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});

		post_view.loadDataWithBaseURL("no-url", "<html></html>", "text/html",
				"utf-8", null);

	}

	private NNTPPost getPostFromView(View view) {
		if (view == null)
			return null;
		LinearLayout view_parent = (LinearLayout) view.getParent();
		if (view_parent == null)
			return null;
		TextView thread_id = (TextView) view_parent.findViewById(R.id.replyid);
		if (thread_id == null)
			return null;

		long t_number = Long.parseLong(thread_id.getText().toString().trim());
		adapter.setMarked(t_number);
		adapter.notifyDataSetChanged();
		Log.d("NNTP", "Get post #" + t_number);
		return NNTPClient.getPostById(t_number);
	}

	public void replyClick(View view) {
		NNTPPost thread = getPostFromView(view);
		if (thread == null)
			return;

		showPost(thread);
	}
}
